package com.test.user.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import com.alibaba.fastjson.JSONObject;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

@Controller
public class AuthController {
	Map<String, String> sessionToUsername = new HashMap<String, String>(); // 一个Session只对应一个Username
	Map<String, String> usernameToSession = new HashMap<String, String>(); // 即一个流览器只有一个hsw_auth_session
	Map<String, String> usernameToToken = new HashMap<String, String>(); // 一个app对应一个code/token
	Map<String, String> tokenToUsername = new HashMap<String, String>();
	Map<String, String> usernameToCode = new HashMap<String, String>(); // 一个app对应一个code/token
	Map<String, String> codeToUsername = new HashMap<String, String>(); // 防止瞎编code

	@RequestMapping(value = "/oauth/authorize", method = RequestMethod.GET, produces = "application/json;carset=UTF-8")
	public Object authorize(@CookieValue(value = "hsw_oauth_session", required = false) String hsw_oauth_session,
			HttpServletRequest request, HttpServletResponse response) throws IOException {
		String redirectCallbackUrl = request.getParameter("redirect_url");
		String clientID = request.getParameter("client_id");
		String appSite = request.getParameter("appsite");
		ModelAndView model = new ModelAndView("login");
		model.addObject("redirectCallbackUrl", redirectCallbackUrl);
		model.addObject("clientID", clientID);
		model.addObject("appSite", appSite);
		if (!clientID.equals("hsw-app1") && !clientID.equals("hsw-app2")) {
			System.out.println("ClientID没注册过");
			return model;
		}
		if (hsw_oauth_session == null || hsw_oauth_session.equals("")) {
			System.out.println("没有hsw_oauth_session，跳转至login");
			return model;
		} else {
			if (sessionToUsername.get(hsw_oauth_session) != null) {
				String code;
				String username = sessionToUsername.get(hsw_oauth_session);
				if (usernameToCode.get(username) != null) {
					code = usernameToCode.get(username);
				} else {
					code = getRandomString(20);
					System.out.println("Put usernameToCode: " + username + ", " + code);
					usernameToCode.put(username, code);
					codeToUsername.put(code, username);
				}
				return new ModelAndView("redirect:" + redirectCallbackUrl + "?code=" + code + "&appsite=" + appSite);
			} else {
				return model;
			}
		}
	}

	@RequestMapping(value = "/oauth/token", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
	public Object token(HttpServletRequest request, HttpServletResponse resp) throws IOException {
		// 获取请求消息体--请求参数
		// 1.获取字符流
		System.out.println("/Oauth/Token......");
		BufferedReader reader = request.getReader();
		// 2.读取数据
		String line = reader.readLine();
		JSONObject p = (JSONObject) JSONObject.parse(line);
		String clientID = p.getString("client_id");
		String code = p.getString("code");
		String clientSecret = p.getString("client_secret");
		String username = codeToUsername.get(code);
		System.out.println("clientID = " + clientID);
		System.out.println(username);
		System.out.println(code);
		if (!codeToUsername.get(code).equals(username)) {
			return new ModelAndView("login");
		} else {
			String accessToken = getRandomString(20);
			JSONObject params = new JSONObject();
			params.put("access_token", accessToken);
			params.put("token_type", "bearer");
			params.put("expires_in", 2592000);
			params.put("refresh_token", code);
			params.put("scope", "read");
			JSONObject info = new JSONObject();
			tokenToUsername.put(accessToken, username);
			usernameToToken.put(username, accessToken);
			info.put("username", username);
			params.put("info", info);
			resp.setCharacterEncoding("utf-8");
			resp.setContentType("application/json; charset=utf-8");
			PrintWriter writer = resp.getWriter();
			System.out.println(params.toString());
			writer.write(params.toString());
			return null;
		}
	}

	@RequestMapping(value = "/oauth/login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
	public void login(HttpServletRequest request, HttpServletResponse resp) throws IOException {
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		if ((username.equals("admin") || username.equals("admin2")) && password.equals("admin")) {
			String randomSession = getRandomString(20);
			sessionToUsername.put(randomSession, username);
			usernameToSession.put(username, randomSession);
			resp.setCharacterEncoding("utf-8");
			resp.setContentType("application/json; charset=utf-8");
			PrintWriter writer = resp.getWriter();
			Cookie authSiteCookie = new Cookie("hsw_oauth_session", randomSession);
			// 设置cookie的持久化时间，60s
			authSiteCookie.setMaxAge(120);
			// 设置为当前项目下都携带这个cookie
			authSiteCookie.setPath("/");
			// 向客户端发送cookie
			resp.addCookie(authSiteCookie);
			JSONObject o = new JSONObject();
			o.put("status", "success");
			writer.write(o.toString());
		}
	}

	@RequestMapping(value = "/oauth/logout", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
	public void logout(HttpServletRequest request, HttpServletResponse resp) throws IOException {
		BufferedReader reader = request.getReader();
		// 2.读取数据
		String line = reader.readLine();
		JSONObject p = (JSONObject) JSONObject.parse(line);
		String accessToken = p.getString("access_token");
		String userName = tokenToUsername.get(accessToken);
		if (userName != null) {
			if (accessToken != null) {
				String code = usernameToCode.get(userName);
				String session = usernameToSession.get(userName);
				sessionToUsername.remove(session);
				usernameToSession.remove(userName);
				usernameToCode.remove(userName);
				codeToUsername.remove(code);
				tokenToUsername.remove(accessToken);
				usernameToToken.remove(userName);
				System.out.println("Remove hsw_oauth_session, username = " + userName);
			}
		}
		resp.setCharacterEncoding("utf-8");
		resp.setContentType("application/json; charset=utf-8");
		PrintWriter writer = resp.getWriter();
		JSONObject o = new JSONObject();
		o.put("status", "success");
		writer.write(o.toString());
	}

	@RequestMapping(value = "/oauth/userinfo", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
	public void getUserinfo(HttpServletRequest request, HttpServletResponse resp) throws IOException {
		BufferedReader reader = request.getReader();
		// 2.读取数据
		String line = reader.readLine();
		JSONObject p = (JSONObject) JSONObject.parse(line);
		String accessToken = p.getString("access_token");
		// AccessToken -> Userinfo
		JSONObject reply = new JSONObject();
		String usernamString = tokenToUsername.get(accessToken);
		String sessionString = usernameToSession.get(usernamString);
		if(usernamString != null && sessionString != null) {
			System.out.println("/oauth/userinfo: token, username := " + accessToken +", "+ usernamString);
			reply.put("username", usernamString);
			reply.put("status", "success");
		}else {
			reply.put("status", "fail");
		}
		resp.setCharacterEncoding("utf-8");
		resp.setContentType("application/json; charset=utf-8");
		PrintWriter writer = resp.getWriter();
		writer.write(reply.toString());
	}

	/**
	 * 生成length长度的randomString
	 */
	public static String getRandomString(int length) {
		Random random = new Random();
		StringBuffer valSb = new StringBuffer();
		String charStr = "0123456789abcdefghijklmnopqrstuvwxyz";
		int charLength = charStr.length();

		for (int i = 0; i < length; i++) {
			int index = random.nextInt(charLength);
			valSb.append(charStr.charAt(index));
		}
		return valSb.toString();
	}
}
